package cn.qingyun.gis.modules.scenes.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.minio.util.MinioTool;
import cn.qingyun.gis.modules.baogan.dto.VisitTotalDto;
import cn.qingyun.gis.modules.baogan.entity.MicrogridCareRecordEntity;
import cn.qingyun.gis.modules.baogan.mapper.MicroStreetDataMapper;
import cn.qingyun.gis.modules.baogan.mapper.MicrogridCareRecordMapper;
import cn.qingyun.gis.modules.baogan.service.MicroStreetDataService;
import cn.qingyun.gis.modules.baogan.service.MicrogridCareRecordService;
import cn.qingyun.gis.modules.baogan.vo.AggRequest;
import cn.qingyun.gis.modules.baogan.vo.MapAggResponse;
import cn.qingyun.gis.modules.baogan.vo.PoiScenarioTypeResponse;
import cn.qingyun.gis.modules.baogan.vo.ScenarioCountResponse;
import cn.qingyun.gis.modules.baogan.vo.request.DataQueryRequest;
import cn.qingyun.gis.modules.baogan.vo.request.SceneRequest;
import cn.qingyun.gis.modules.baogan.vo.response.DataResponse;
import cn.qingyun.gis.modules.baogan.vo.response.EnterpriseResponse;
import cn.qingyun.gis.modules.baogan.vo.response.MGridDetailRes;
import cn.qingyun.gis.modules.baogan.vo.response.PointDetailRes;
import cn.qingyun.gis.modules.express.util.SyncTool;
import cn.qingyun.gis.modules.scenes.contant.ComConstant;
import cn.qingyun.gis.modules.scenes.contant.ExcutorType;
import cn.qingyun.gis.modules.scenes.contant.ScenesStatus;
import cn.qingyun.gis.modules.scenes.contant.TypeStatus;
import cn.qingyun.gis.modules.scenes.entity.*;
import cn.qingyun.gis.modules.scenes.mapper.PoiScenarioMapper;
import cn.qingyun.gis.modules.scenes.mapper.PoiScenarioTempMapper;
import cn.qingyun.gis.modules.scenes.mapper.RegionAddrMapper;
import cn.qingyun.gis.modules.scenes.request.*;
import cn.qingyun.gis.modules.scenes.response.*;
import cn.qingyun.gis.modules.scenes.service.*;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.xml.bind.DatatypeConverter;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author guest
 * @since 2024-04-27
 */
@Slf4j
@Service
@DS("scenes_offensive")
public class PoiScenarioServiceImpl extends ServiceImpl<PoiScenarioMapper, PoiScenario> implements IPoiScenarioService {
    //高德统一标准地址库 id查询
    private static final String AMAP_ADDRESS_QUERY_DETAIL = "/amap/address/query/detail?id=";
    private static final String BASE64_HEADER = "data:image/jpeg;base64,";

    @Value("${qingyun.gd.service-host}")
    private String gdServiceHost;

    @Autowired
    private PoiScenarioMapper poiScenarioMapper;
    @Autowired
    private PoiScenarioTempMapper poiScenarioTempMapper;

    @Autowired
    private IPoiScenarioAppendixService iPoiScenarioAppendixService;

    @Autowired
    private IPoiScenarioProofreadService iPoiScenarioProofreadService;

    @Resource
    private ISchemaService iSchemaService;
    @Resource
    UniAddrRegionService reginService;
    @Resource
    private RegionAddrMapper regionAddrMapper;

    @Resource
    MicrogridCareRecordService microgridCareRecordService;
    @Resource
    private UniAddrRegionService uniAddrRegionService;


    @Resource
    MicrogridCareRecordMapper microgridCareRecordMapper;
    @Resource
    private MicroStreetDataMapper microStreetDataMapper;
    @Resource
    private MicroStreetDataService microStreetDataService;


    /**
     * 通过id查询任务详情
     *
     * @param id
     * @return
     */
    @Override
    public TaskDetailResponse queryTaskDetailById(String id) {
        TaskDetailResponse response = poiScenarioMapper.queryTaskDetailById(id);
        if (ObjectUtil.isNotEmpty(response)) {
            try {
                if (StringUtils.isNotEmpty(response.getKwRelativesInfo())) {
                    List<KwRelativesDto> kwRelativesList = JSON.parseArray(response.getKwRelativesInfo(), KwRelativesDto.class);
                    response.setKwRelationInfoList(kwRelativesList);
                }
            } catch (Exception e) {
                throw new CommonException("亲属关系解析失败");
            }
            // 商机内容（录音识别）
            try {
                if (StringUtils.isNotEmpty(response.getContentList())) {
                    List<BusContentDto> busContentDtoList = JSON.parseArray(response.getContentList(), BusContentDto.class);
                    response.setBusinessContentList(busContentDtoList);
                }
            } catch (Exception e) {
                throw new CommonException("商机内容（录音识别）解析失败");
            }
            // 获取附件信息
            QueryWrapper<PoiScenarioAppendix> poiStreetAppendixQueryWrapper = new QueryWrapper<>();
            poiStreetAppendixQueryWrapper.lambda().eq(PoiScenarioAppendix::getPoiScenarioId, id).eq(PoiScenarioAppendix::getProofreadId, response.getProofreadId()).orderByDesc(PoiScenarioAppendix::getCreateTime);
            response.setAppendixInfos(BeanUtil.copyToList(iPoiScenarioAppendixService.list(poiStreetAppendixQueryWrapper), AppendixResponse.class));
            log.debug("获取附件信息完毕，{}", id);
        }
        // 进行base64字符串返回
        if (ObjectUtil.isNotEmpty(response.getAppendixInfos())) {
            List<ImageResponse> base64Infos = Lists.newArrayList();
            response.getAppendixInfos().forEach(item -> {
                if (TypeStatus.PHOTO.getDesc().equals(item.getType())) {
                    byte[] imageBytes = new byte[0];
                    try {
                        imageBytes = MinioTool.fetchLocalBytes(item.getMinioPath());
                        log.debug("附件返回完毕！");
                    } catch (Exception e) {
                        log.debug("minio服务解析图片返回byte数组失败~");
                    }
                    if (imageBytes != null && imageBytes.length > 0) {
                        String base64Image = BASE64_HEADER + DatatypeConverter.printBase64Binary(imageBytes);
                        if (CharSequenceUtil.isNotEmpty(base64Image)) {
                            base64Infos.add(ImageResponse.builder()
                                    .minioPath(item.getMinioPath())
                                    .base64(base64Image)
                                    .build());
                        }
                    }

                }
            });

            response.setBase64Infos(base64Infos.stream()
                    .sorted(Comparator.comparing(
                            obj -> obj.getMinioPath().split("_")[obj.getMinioPath().split("_").length - 1]
                    )).collect(Collectors.toList()));
        }
        return response;
    }

    @Override
    public PoiInfoDetailResponse queryPoiInfoDetailById(PoiInfoDetailRequest poiInfoDetailRequest, String table) {
        return this.baseMapper.queryPoiInfoDetailById(poiInfoDetailRequest, table);
    }

    /**
     * 通过gdId查询地址详情
     *
     * @param gdId
     * @return
     */
    @Override
    public AddressResponse queryAddressDetailByGdId(String gdId) {
        String url = gdServiceHost + AMAP_ADDRESS_QUERY_DETAIL + gdId;
        HttpRequest httpRequest = HttpUtil.createGet(url);
        try {
            HttpResponse httpResponse = httpRequest.timeout(1000).execute();
            if (httpResponse.isOk()) {
                JSONObject parseObj = JSONUtil.parseObj(httpResponse.body());
                JSONObject parseObjByPath = parseObj.getByPath("data[0]", JSONObject.class);
                if (!parseObjByPath.isEmpty()) {
                    String kwCity = parseObjByPath.getByPath("city", String.class);
                    String kwDis = parseObjByPath.getByPath("district", String.class);
                    String kwTown = parseObjByPath.getByPath("town", String.class);
                    String kwRoad = parseObjByPath.getByPath("road", String.class);
                    String kwRoadNo = parseObjByPath.getByPath("roadNo", String.class);

                    return AddressResponse.builder()
                            .kwCity(kwCity)
                            .kwDis(kwDis)
                            .kwTown(kwTown)
                            .kwRoad(kwRoad)
                            .kwRoadNo(kwRoadNo)
                            .build();
                }
            }

        } catch (Exception e) {
            log.warn("获取高德结构化地址失败~");
        }


        return null;
    }

    @Override
    public List<ScenesExportDto> selectDetailPage(long num, long size, String code, int level) {
        return poiScenarioMapper.selectDetailPage(num, size, code, level);
    }

    @Override
    public List<ScenesExportDto> selectCityDetail(String disCode) {
        return poiScenarioMapper.selectCityDetail(disCode);
    }

    @Override
    public List<ScenesPageDto> selectDetailCondPage(int num, int size, String code, Integer level, String kwPhone, Integer kwState) {
        return poiScenarioMapper.selectDetailCondPage(num, size, code, level, kwPhone, kwState);
    }

    @Override
    public List<ScenesPageDto> selectDetailCondPageNew(PoiChannelRequest poiChannelRequest, List<String> tables, Integer level) {
        return poiScenarioMapper.selectDetailCondPageNew(poiChannelRequest, tables, level);
    }

    @Override
    public List<ScenesPageDto> selectDetailCondNewSub(PoiChannelRequest poiChannelRequest, List<String> tables, Integer level) {
        return poiScenarioMapper.selectDetailCondNewSub(poiChannelRequest, tables, level);
    }

    @Override
    public int selectDetailCount(String code, Integer level, String kwPhone, Integer kwState) {
        return poiScenarioMapper.selectDetailCount(code, level, kwPhone, kwState);
    }

    /**
     * 计算全量摸排数据个数
     *
     * @param poiChannelRequest
     * @param table
     * @return
     */
    @Override
    public int selectDetailCountNew(PoiChannelRequest poiChannelRequest, String table, Integer level) {
        return poiScenarioMapper.selectDetailCountNew(poiChannelRequest, table, level);
    }

    @Override
    public List<PoiSceneCount> selectSceneCount(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectSceneCount(poiCountRequest, table, level);
    }

    @Override
    public List<PoiSceneCount> selectSceneCountSub(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectSceneCountSub(poiCountRequest, table, level);
    }

    @Override
    public Integer selectKdClientTotal(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectKdClientNum(poiCountRequest, table, level);
    }

    @Override
    public Integer selectMyselfNumber(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectMyselfKwCount(poiCountRequest, table, level);
    }

    @Override
    public List<PoiSceneCount> selectSpecificSceneCount(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectSpecificSceneCount(poiCountRequest, table, level);
    }

    @Override
    public List<PoiSceneCount> selectSpecificSceneKwPoiCount(PoiCountRequest poiCountRequest, String table, Integer level) {
        return poiScenarioMapper.selectSpecificSceneKwPoiNum(poiCountRequest, table, level);
    }

    @Override
    public List<IndexAroundResponse> poiIndexQuery(IndexAroundNewRequest request, String table, Integer Level, String code) {
        return poiScenarioMapper.selectIndexQuery(request, table, Level, code);
    }

    @Override
    public List<PoiSceneCount> selectBuildCount(List<String> poiIds) {
        return poiScenarioMapper.selectBuildCountTotal(poiIds);
    }

    @Override
    public List<KwPeopleRecord> kwPeopleRecordSelect(String id, String table, String type) {
        List<TaskDetailResponse> taskDetailResponses = poiScenarioMapper.kwPeopleRecordQuery(id, table);
        ArrayList<KwPeopleRecord> records = Lists.newArrayList();
        BelongPeopleResponse response = iPoiScenarioProofreadService.selectBelongKwPhone(id, type);
        log.debug("管理后台随访记录归属人信息，{}", response);
        String belongId = null;
        if (response != null) {
            belongId = response.getId();
        }
        //对归属字段进行赋值
        String finalBelongId = belongId;
        taskDetailResponses.forEach(taskDetailResponse -> {
            KwPeopleRecord kwPeopleRecord = new KwPeopleRecord();
            BeanUtils.copyProperties(taskDetailResponse, kwPeopleRecord);
            if (StringUtils.isNotEmpty(finalBelongId) && taskDetailResponse.getProofreadId().equals(finalBelongId)) {
                kwPeopleRecord.setBelongFlag(1);
            }
            records.add(kwPeopleRecord);
        });
        return records;
    }

    @Override
    public List<TogetherResponse> selectTogetherData(IndexTogetherRequest request, Integer level) {
        String table = ComConstant.TABLES.get(0);
        return poiScenarioMapper.selectListData(request, level, table);
    }

    @Override
    public IPage<PoiListResponse> selectPoiSettledPage(IPage<PoiScenario> poiIPage, PoiPageRequest request) {
        return poiScenarioMapper.selectPoiSettledPagePoi(poiIPage, request);
    }

    @Override
    public List<BuildingDetailResponse> buildingDetailSelect(BuildDetailRequest request) {
        return poiScenarioMapper.selectBuildingDetail(request);
    }

    /**
     * 新增或者更新poi数据
     *
     * @param request 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdatePoi(PoiScenarioRequest request) {
        log.debug("新增或更新poi传入的参数{}", request);
        LambdaQueryWrapper<PoiScenario> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PoiScenario::getId, request.getId()).eq(PoiScenario::getPoiId, request.getPoiId());
        PoiScenario poiScenarioOld = poiScenarioMapper.selectOne(wrapper);
        PoiScenario poiScenario = new PoiScenario();
        BeanUtils.copyProperties(request, poiScenario);
        //更新操作
        if (poiScenarioOld != null) {
            poiScenario.setKwState(poiScenarioOld.getKwState());
            poiScenario.setUpdateTime(poiScenarioOld.getUpdateTime());
            //先删除数据再新增进去，防止地市改变，入表失败
            int delete = poiScenarioMapper.delete(wrapper);
            boolean result = this.save(poiScenario);
            log.debug("更新poi传入的参数{},删除结果{}，保存结果{}", request, delete, result);
        } else {
            //新增数据操作
            boolean result = this.save(poiScenario);
            log.debug("新增poi传入的参数{},保存结果{}", request, result);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void poiDelete(PoiDeleteRequest request) {
        log.debug("删除poi入参{}", request);
        LambdaQueryWrapper<PoiScenario> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PoiScenario::getPoiId, request.getPoiId());
        PoiScenario poiScenario = poiScenarioMapper.selectOne(wrapper);
        String id = poiScenario.getId();
        //1.删除原数据
        int delete = poiScenarioMapper.delete(wrapper);
        //2.删除摸排记录表
        LambdaQueryWrapper<PoiScenarioProofread> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PoiScenarioProofread::getPoiScenarioId, id);
        boolean proofreadResult = iPoiScenarioProofreadService.remove(queryWrapper);
        //3.附件记录表删除
        LambdaQueryWrapper<PoiScenarioAppendix> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PoiScenarioAppendix::getPoiScenarioId, id);
        boolean appendixResult = iPoiScenarioAppendixService.remove(lambdaQueryWrapper);
        log.debug("删除poi入参{}，原数据删除结果{}，摸排记录删除结果{},附件记录表删除结果{}", request, delete, proofreadResult, appendixResult);
    }

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void poiQuarterUpdate() {
        log.debug("季度更新开始时间：{}", DateUtil.format(DateUtil.date(), "yyyy/MM/dd HH:mm:ss"));
        int batchSize = 3000;
        for (int index = 0; index < ComConstant.CITY_List.size(); index++) {
            String regionCityCode = ComConstant.CITY_List.get(index);
            //查询该地市下的所有区县
            List<String> districtCodes = poiScenarioTempMapper.selectDistrictCodeByCityCode(regionCityCode);
            for (String districtCode : districtCodes) {
                log.debug("开始执行的地市码,区县码，{}，{}", regionCityCode, districtCode);
                LambdaQueryWrapper<PoiScenarioTemp> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(PoiScenarioTemp::getRegionCityCode, regionCityCode);
                wrapper.eq(PoiScenarioTemp::getRegionDisCode, districtCode);
                int selectCount = poiScenarioTempMapper.selectCount(wrapper);
                int pages = selectCount / batchSize + 1;
                if (selectCount <= 0) {
                    continue;
                }
                SyncTool.doSync(pages, i -> {
                    int startIndex = (i - 1) * batchSize;
                    log.debug("进入更新poi数据处理{},{},{},{}", regionCityCode, districtCode, startIndex, batchSize);
                    //1.poi_scenes_temp表取1000条数据
                    List<PoiScenario> originalData = poiScenarioTempMapper.selectPoiScenarioList(regionCityCode, districtCode, startIndex, batchSize);
                    List<String> poiIdList = originalData.stream().map(PoiScenario::getPoiId).collect(Collectors.toList());
                    //2.根据这1000个poiId去poi_scenario_l?表查询公共的部分
                    List<PoiScenario> poiIdCommonList = poiScenarioMapper.selectPoiIdCommonEntity(regionCityCode, poiIdList);
                    log.debug("公共部分大小{}", poiIdCommonList.size());
                    List<String> commonPoiList = poiIdCommonList.stream().map(PoiScenario::getPoiId).collect(Collectors.toList());
                    //3.对于已随访/建筑的poi,将新数据的id,kw_state,update_time列更新为老数据
                    Map<String, PoiScenario> commonPoiMap = poiIdCommonList.stream()
                            .collect(Collectors.toMap(PoiScenario::getPoiId, poiScenario -> poiScenario));
                    originalData.forEach(poiScenario -> {
                        String poiId = poiScenario.getPoiId();
                        PoiScenario commonPoi = commonPoiMap.get(poiId);
                        if (commonPoiMap.containsKey(poiId) && (commonPoi.getKwState() == 1 || commonPoi.getIsBuild() == 1)) {
                            poiScenario.setId(commonPoi.getId());
                            poiScenario.setKwState(commonPoi.getKwState());
                            poiScenario.setUpdateTime(commonPoi.getUpdateTime());
                        }
                    });
                    log.debug("处理完的集合{}", originalData);
                    //4.删除poi_scenario_l?表老数据
                    if (CollectionUtils.isNotEmpty(commonPoiList)) {
                        log.debug("进入删除===》");
                        poiScenarioMapper.deletePoiData(commonPoiList, regionCityCode);
                    }
                    //5.插入处理完的数据
                    List<PoiScenario> collect = originalData.stream().filter(poiScenario -> commonPoiList.contains(poiScenario.getPoiId())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(collect)) {
                        DynamicDataSourceContextHolder.push("scenes_offensive");
                        try {
                            boolean result = this.saveBatch(collect);
                        } finally {
                            //强制清空本地线程
                            DynamicDataSourceContextHolder.clear();
                        }
                    }
                    //6.找出与原数据对比新增的数据
                    List<PoiScenario> collectAdd = originalData.stream().filter(poiScenario -> !commonPoiList.contains(poiScenario.getPoiId())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(collectAdd)) {
                        DynamicDataSourceContextHolder.push("scenes_offensive");
                        try {
                            //先删除分布在poi_scenario_l?中原来的数据,再插入新数据
                            List<String> deleteCollect = collectAdd.stream().map(PoiScenario::getPoiId).collect(Collectors.toList());
                            Boolean deleteResult = poiScenarioMapper.deletePoiData(deleteCollect, null);
                            log.info("要删除的集合大小{},删除结果{}", collectAdd.size(), deleteResult);
                            boolean result = this.saveBatch(collectAdd);
                        } finally {
                            //强制清空本地线程
                            DynamicDataSourceContextHolder.clear();
                        }
                    }
                });
            }
        }
        log.debug("季度更新结束时间：{}", DateUtil.format(DateUtil.date(), "yyyy/MM/dd HH:mm:ss"));
    }

    @Override
    public void poiQuarterUpdateNew() {
        int batchSize = 3000;
        log.info("季度更新开始时间：{}", DateUtil.format(DateUtil.date(), "yyyy/MM/dd HH:mm:ss"));
        //TODO 1.备份原数据16个表
        //TODO 2.将原16个表改名 poi_scenario_la_old等
        //TODO 3.从季度更新数据临时表中根据地市生成16个表 poi_scenario_la等
        SyncTool.doSync(16, index -> {
            String tableName = ComConstant.TABLE_List.get(index - 1);
            iSchemaService.executeSqlScript(ExcutorType.PREPAREDSTATEMENT, "scenes_offensive", "CREATE TABLE poi_scenario_la_1 (LIKE poi_scenario_la INCLUDING ALL)");
            iSchemaService.executeSqlScript(ExcutorType.PREPAREDSTATEMENT, "scenes_offensive", "INSERT INTO public.poi_scenario_la_1 (poi_id, poi_lng, poi_lat, poi_name, city_adcode, district_adcode, multi_addr_chn, category_ids, category_names, \"type\", points, region_city, region_city_code, region_dis, region_dis_code, grid_code, grid_name, aoi, telephone, address, id, kw_state, update_time, create_time, belong_build_id, micro_grid_code, micro_grid_name, town_name, town_code, is_build)  SELECT poi_id, poi_lng, poi_lat, poi_name, city_adcode, district_adcode, multi_addr_chn, category_ids, category_names, \"type\", points, region_city, region_city_code, region_dis, region_dis_code, grid_code, grid_name, aoi, telephone, address, id, kw_state, update_time, create_time, belong_build_id, micro_grid_code, micro_grid_name, town_name, town_code, is_build FROM sync.poi_scenes_temp where region_city_code='SD.LA'");
        });

        log.info("季度更新结束时间：{}", DateUtil.format(DateUtil.date(), "yyyy/MM/dd HH:mm:ss"));
    }

    @Override
    public PoiScenario getNearestPoiData(String points) {
        return poiScenarioMapper.getPoiData(points);
    }

    /**
     * 更新建筑和企业摸排随访状态
     *
     * @param
     * @param type
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateKwState(String id, String type, String regionCityCode, Integer isBuild) {
        if (!type.equals(ScenesStatus.STREET.getDesc())) {
            //查询企业是否有归属建筑
            LambdaQueryWrapper<PoiScenario> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(PoiScenario::getPoiId, PoiScenario::getId, PoiScenario::getKwMixState, PoiScenario::getBelongBuildId, PoiScenario::getIsBuild, PoiScenario::getRegionCityCode)
                    .eq(PoiScenario::getId, id)
                    .eq(PoiScenario::getRegionCityCode, regionCityCode);
            PoiScenario poiScenario = poiScenarioMapper.selectOne(wrapper);
            if (poiScenario != null) {
                String belongBuildId = poiScenario.getBelongBuildId();
                if (StringUtils.isNotEmpty(belongBuildId)) {
                    //查询归属建筑下所有（企业+自身建筑）是否都随访
                    Integer count = poiScenarioMapper.selectKwStateCount(belongBuildId, poiScenario.getRegionCityCode());
                    if (count != null && count == 0) {
                        //修改建筑那条数据的随访状态
                        PoiScenario poiScenarioBuild = new PoiScenario();
                        poiScenarioBuild.setPoiId(belongBuildId);
                        UpdateWrapper<PoiScenario> buildUpdateWrapper = new UpdateWrapper<>();
                        buildUpdateWrapper.set("kw_mix_state", ComConstant.FINISH_KW);
                        buildUpdateWrapper.eq("poi_id", belongBuildId);
                        int update = poiScenarioMapper.update(null, buildUpdateWrapper);
                    }
                }
            }
        }
        if (isBuild == 0) {
            UpdateWrapper<PoiScenario> wrapperUpdate = new UpdateWrapper<>();
            wrapperUpdate.eq("id", id);
            wrapperUpdate.eq("region_city_code", regionCityCode);
            wrapperUpdate.set("kw_mix_state", ComConstant.FINISH_KW);
            int update = poiScenarioMapper.update(null, wrapperUpdate);
            log.info("修改{}随访状态结果{}", id, update);
        }
    }

    @Override
    public List<PoiScenario> selectChangedPoiData(String id, String regionCityCode) {
        return poiScenarioMapper.selectChangedListData(id, regionCityCode);
    }

    @Override
    public List<PoiScenario> selectMircoChangedPoiData(String id, String regionCityCode) {
        return poiScenarioMapper.selectMicroChangedListData(id, regionCityCode);
    }

    @Override
    public List<MapAggResponse> selectAggList(AggRequest request) {
        log.debug("管理后台聚合接口入参{}", request);
        BigDecimal rtLon = request.getRtLon();
        BigDecimal rtLat = request.getRtLat();
        BigDecimal lbLon = request.getLbLon();
        BigDecimal lbLat = request.getLbLat();
        Integer flag = uniAddrRegionService.selectLevel(request.getCode());
        List<String> processedTypes = request.getTypes();
        if (ObjectUtil.isNotNull(processedTypes)) {
            if (processedTypes.contains(ScenesStatus.BUSINESS.getDesc())) {
                processedTypes.add(ScenesStatus.COMPLEX.getDesc());
            }
        }
        ArrayList<MapAggResponse> resultList = Lists.newArrayList();
        request.setTypes(processedTypes);
        //查所有的数据
        List<MapAggResponse> list = poiScenarioMapper.selectAggList(request, flag, request.getLevel());
        //找出可视范围的区划信息
        QueryWrapper<UniAddrRegion> wrapper = new QueryWrapper<>();
        wrapper.select("id", "code", "name", "ST_X(center_point) AS lon", "ST_Y(center_point) AS lat").ne("state", -1).eq("level", request.getLevel())
                .apply(String.format("ST_Within(center_point,ST_GeomFromText('MULTIPOLYGON(((%s %s,%s %s,%s %s,%s %s,%s %s)))',4326))", lbLon, lbLat, lbLon, rtLat, rtLon, rtLat, rtLon, lbLat, lbLon, lbLat));
//        List<UniAddrRegion> uniAddrRegionList = uniAddrRegionService.getBaseMapper().selectList(wrapper);
        List<UniAddrRegion> uniAddrRegionList = getRegionListByCode(flag,request.getLevel(),request.getCode(),lbLon,lbLat,rtLon,rtLat);
        Map<String, MapAggResponse> mapAggResponseMap = list.stream()
                .collect(Collectors.toMap(MapAggResponse::getCode, mapAggResponse -> mapAggResponse));
        uniAddrRegionList.forEach(uniAddrRegion -> {
            MapAggResponse mapAggResponse = mapAggResponseMap.get(uniAddrRegion.getCode());
            if (mapAggResponse != null) {
                mapAggResponse.setName(uniAddrRegion.getName());
                mapAggResponse.setPoiLng(uniAddrRegion.getLon());
                mapAggResponse.setPoiLat(uniAddrRegion.getLat());
                mapAggResponse.setWkt(uniAddrRegion.getWkt());
                resultList.add(mapAggResponse);
            }
        });
        log.debug("管理后台聚合接口返回集合大小{}", resultList.size());
        return resultList;
    }
    //根据权限返回能查询到的区县网格
    private List<UniAddrRegion> getRegionListByCode(Integer level, Integer flag, String codeStr,BigDecimal lbLon,BigDecimal lbLat,BigDecimal rtLon,BigDecimal rtLat) {
        List<UniAddrRegion> list = Lists.newArrayList();
        if (level > 4) {
            throw new CommonException("传入的编码不对！");
        }
        //网格数据
        String gridCode = null;
        if (level == 4) {
            gridCode = codeStr;
            UniAddrRegion uniAddrRegion = uniAddrRegionService.selectRegionByCode(codeStr);
            codeStr = uniAddrRegion.getParentCode();
        }
        String[] parts = codeStr.split("\\.");
        if (flag > parts.length) {
            codeStr = String.join(".", parts);
        } else {
            codeStr = String.join(".", Arrays.copyOf(parts, flag));
        }
        if (flag == 1) { // 省级聚合
            list = uniAddrRegionService.selectRegionListSub(flag, codeStr,lbLon,lbLat,rtLon,rtLat);
        } else if (flag == 2) { // 市级聚合
            list = uniAddrRegionService.selectRegionListSub(flag, codeStr,lbLon,lbLat,rtLon,rtLat);
        } else if (flag == 3) { // 区级聚合
            list = uniAddrRegionService.selectRegionListSub(flag, codeStr,lbLon,lbLat,rtLon,rtLat);
        } else if (flag == 4) { // 网格级聚合
            list = uniAddrRegionService.selectRegionByParentCodeListSub(flag, codeStr,lbLon,lbLat,rtLon,rtLat);
            if (StringUtils.isNotEmpty(gridCode)) {
                String finalGridCode = gridCode;
                list = list.stream().filter(regionAddr -> regionAddr.getCode().equals(finalGridCode)).collect(Collectors.toList());
            }
        }else if(flag==5){
            List<UniAddrRegion> microgridList=null;
            if (level<=3){
                microgridList = uniAddrRegionService.selectRegionByParentCodeListSub(4, codeStr,lbLon,lbLat,rtLon,rtLat);
            }
            if (level==4){
                microgridList = uniAddrRegionService.selectRegionByParentCodeListSub(4, codeStr,lbLon,lbLat,rtLon,rtLat);
            }
            if (CollectionUtils.isNotEmpty(microgridList)){
                List<String> collect = microgridList.stream().map(UniAddrRegion::getCode).collect(Collectors.toList());
                QueryWrapper<UniAddrRegion> wrapper = new QueryWrapper<>();
                wrapper.select("id","code","parent_code","name","ST_X(center_point) AS lon", "ST_Y(center_point) AS lat","ST_AsText(wkt) AS wkt")
                        .ne("state",-1).eq("level",5)
                        .in("parent_code",collect)
                        .apply(String.format("ST_Intersects(wkt,ST_GeomFromText('MULTIPOLYGON(((%s %s,%s %s,%s %s,%s %s,%s %s)))',4326))", lbLon, lbLat, lbLon, rtLat, rtLon, rtLat, rtLon, lbLat, lbLon, lbLat));
                list = uniAddrRegionService.getBaseMapper().selectList(wrapper);
            }
        }
        return list;
    }

    @SneakyThrows
    public List<UniAddrRegion> selectRegionList(String code, Integer flag) {
        List<UniAddrRegion> list = Lists.newArrayList();
        if (flag == 1) { // 省级聚合
            list = uniAddrRegionService.selectProvinceByCode(1);
        } else {
            list = uniAddrRegionService.selectUniAddrByCode(code, flag);
        }
        return list;
    }


    /**
     * 统计场景数量----统计的信息来源是自己画的加路网数据
     * @return
     */
    public List<ScenarioCountResponse> aggScenario(String code, Integer flag) {
        Integer level = uniAddrRegionService.selectLevel(code);
        return microStreetDataMapper.selectLWCount(code, flag, level);
    }

    /**
     * 统计场景列表---统计的信息来源是自己画的加路网数据
     * @return
     */
    @Override
    public Page<PoiScenarioTypeResponse> selectSceneList(SceneRequest request) {
        Page<PoiScenarioTypeResponse> page = new Page<>(request.getPageNum(), request.getPageSize());
        String code = request.getCode();
        Integer level = uniAddrRegionService.selectLevel(code);
        Page<PoiScenarioTypeResponse> list = microStreetDataMapper.selectSceneList(page, request.getCode(), request.getType(), level, request.getFlag());
        return list;
    }


    /**
     * 查询微网格详情
     * @param microGridCode
     * @param id
     * @return
     */
    @Override
    public MGridDetailRes selectMicroDetail(String microGridCode, String id) {
        // 异步获取建筑数量
        CompletableFuture<Integer> buildingTotalFuture = CompletableFuture.supplyAsync(() ->
                        poiScenarioMapper.selectMGBuildingTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("获取建筑数量异常: {}", e.getMessage(), e);
                    return 0;
                });

        // 异步获取企业数量
        CompletableFuture<Integer> enterpriseTotalFuture = CompletableFuture.supplyAsync(() ->
                        poiScenarioMapper.selectMGEnterpriseTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("获取企业数量异常: {}", e.getMessage(), e);
                    return 0;
                });

        // 异步获取未随访和已随访数量
        CompletableFuture<VisitTotalDto> visitTotalFuture = CompletableFuture.supplyAsync(() ->
                        poiScenarioMapper.selectMGVisitTotal(microGridCode, id))
                .exceptionally(e -> {
                    log.error("获取未随访和已随访数量异常: {}", e.getMessage(), e);
                    return new VisitTotalDto(0, 0); // 返回默认值
                });

        // 异步去查询微网格的看管人员
        CompletableFuture<List<MicrogridCareRecordEntity>> custodiansFuture = CompletableFuture.supplyAsync(() ->
                        microgridCareRecordMapper.selectMGCustodians(microGridCode, id))
                .exceptionally(e -> {
                    log.error("查询微网格的看管人员异常: {}", e.getMessage(), e);
                    return Collections.emptyList(); // 返回空列表
                });

        // 当所有异步操作都完成时，设置结果
        CompletableFuture<MGridDetailRes> resultFuture = CompletableFuture.allOf(buildingTotalFuture, enterpriseTotalFuture, visitTotalFuture, custodiansFuture)
                .thenApply((Void) -> {
                    MGridDetailRes res = poiScenarioMapper.selectMicroDetail(microGridCode, id);
                    if (ObjectUtil.isNull(res)) {
                        res = new MGridDetailRes();
                    }
                    // 获取异步操作的结果
                    Integer buildingTotal = buildingTotalFuture.join();
                    Integer enterpriseTotal = enterpriseTotalFuture.join();
                    VisitTotalDto visitTotalDto = visitTotalFuture.join();
                    List<MicrogridCareRecordEntity> careList = custodiansFuture.join();

                    if (ObjectUtil.isNotNull(buildingTotal)) {
                        res.setBuildingTotal(buildingTotal);
                    }
                    if (ObjectUtil.isNotNull(enterpriseTotal)) {
                        res.setEnterpriseTotal(enterpriseTotal);
                    }
                    if (ObjectUtil.isNotNull(visitTotalDto)) {
                        res.setNoVisitedTotal(visitTotalDto.getNoVisitedTotal());
                    }
                    if (ObjectUtil.isNotNull(visitTotalDto)) {
                        res.setVisitedTotal(visitTotalDto.getVisitedTotal());
                    }
                    if (ObjectUtil.isNotNull(careList)) {
                        res.setCustodians(careList);
                    }
                   return res;
                }).exceptionally(e -> {
                    log.error("异步任务中发生异常: {}", e);
                    throw new RuntimeException("异步任务中发生异常", e);
                });

        try {
            return resultFuture.get();
        } catch (Exception e) {
            log.debug("查询微网格详情异常={}", e);
            throw new RuntimeException("异步编排查询微网格详情错误={}", e);
        }
    }

    @Override
    public List<EnterpriseResponse> selectMicroEnterpriseList(String microGridCode, String id) {
        if (StringUtils.isNotEmpty(id)){//查询面数据
            return microStreetDataService.selectEnterpriseList(id);
        }else {
            Integer flag = uniAddrRegionService.selectLevel(microGridCode);
            return poiScenarioMapper.selectEnterpriseList(microGridCode,flag);
        }

    }

    @Override
    public List<DataResponse> selectPoiData(DataQueryRequest request, Integer level) {
        return poiScenarioMapper.selectPoiDataInfo(request, level);
    }

    @Override
    public List<DataResponse> selectPoiDataByMicroCode(String code,String regionCityCode,List<String> types) {
        return poiScenarioMapper.selectMicroPoiDataInfo(code,regionCityCode,types);
    }

    @Override
    public PointDetailRes selectPointDetail(String microGridCode, String id) {
        //异步查询看管人员
        CompletableFuture<List<MicrogridCareRecordEntity>> custodiansFuture = CompletableFuture.supplyAsync(() ->
                microgridCareRecordMapper.selectPointCustodians(microGridCode, id))
                .exceptionally(e -> {
                    log.error("异步查询看管人员: {}", e.getMessage(), e);
                    return Collections.emptyList();
                });
        //查询微网格是否已经被看管划分
        CompletableFuture<Integer> cardFlagFuture = CompletableFuture.supplyAsync(() ->
                        microgridCareRecordMapper.slectMicroCareFlag(microGridCode,id))
                .exceptionally(e -> {
                    log.error("查询微网格是否被看管划分标识: {}", e.getMessage(), e);
                    return 0;
                });

        // 当所有异步操作都完成时，设置结果
        CompletableFuture<PointDetailRes> resultFuture = CompletableFuture.allOf(custodiansFuture,cardFlagFuture)
                .thenApply((Void) -> {
                    PointDetailRes res = poiScenarioMapper.selectPointDetail(microGridCode, id);
                    if (ObjectUtil.isNull(res)){
                        res = new PointDetailRes();
                    }
                    List<MicrogridCareRecordEntity> careList = custodiansFuture.join();
                    Integer careFlag = cardFlagFuture.join();

                    if (ObjectUtil.isNotNull(careList)) {
                        res.setCustodians(careList);
                    }
                    if (ObjectUtil.isNotNull(careFlag)){
                        res.setMicroCareFlag(careFlag);
                    }
                    return res;
                });
        try {
            return resultFuture.get();
        } catch (Exception e) {
            throw new RuntimeException("异步编排查询微网格详情错误={}", e);
        }
    }
}


